aboutsummaryrefslogtreecommitdiff
path: root/src/routes/user/[user]/badges
diff options
context:
space:
mode:
authorFuwn <[email protected]>2024-10-09 00:41:20 -0700
committerFuwn <[email protected]>2024-10-09 00:41:43 -0700
commit998b63a35256ac985a5a2714dd1ca451af4dfd8a (patch)
tree50796121a9d5ab0330fdc5d7e098bda2860d9726 /src/routes/user/[user]/badges
parentfeat(graphql): add badgeCount field (diff)
downloaddue.moe-998b63a35256ac985a5a2714dd1ca451af4dfd8a.tar.xz
due.moe-998b63a35256ac985a5a2714dd1ca451af4dfd8a.zip
chore(prettier): use spaces instead of tabs
Diffstat (limited to 'src/routes/user/[user]/badges')
-rw-r--r--src/routes/user/[user]/badges/+page.gql54
-rw-r--r--src/routes/user/[user]/badges/+page.svelte2040
2 files changed, 1047 insertions, 1047 deletions
diff --git a/src/routes/user/[user]/badges/+page.gql b/src/routes/user/[user]/badges/+page.gql
index afdd797d..060b38e7 100644
--- a/src/routes/user/[user]/badges/+page.gql
+++ b/src/routes/user/[user]/badges/+page.gql
@@ -1,31 +1,31 @@
query BadgeWallUser($id: Int!) {
- User(id: $id) {
- id
+ User(id: $id) {
+ id
- badges {
- post
- image
- description
- id
- time
- category
- hidden
- source
- designer
- shadow_hidden
- click_count
- }
+ badges {
+ post
+ image
+ description
+ id
+ time
+ category
+ hidden
+ source
+ designer
+ shadow_hidden
+ click_count
+ }
- preferences {
- created_at
- updated_at
- user_id
- pinned_hololive_streams
- hide_missing_badges
- biography
- badge_wall_css
- hide_awc_badges
- pinned_badge_wall_categories
- }
- }
+ preferences {
+ created_at
+ updated_at
+ user_id
+ pinned_hololive_streams
+ hide_missing_badges
+ biography
+ badge_wall_css
+ hide_awc_badges
+ pinned_badge_wall_categories
+ }
+ }
}
diff --git a/src/routes/user/[user]/badges/+page.svelte b/src/routes/user/[user]/badges/+page.svelte
index 3857d18b..44dd852a 100644
--- a/src/routes/user/[user]/badges/+page.svelte
+++ b/src/routes/user/[user]/badges/+page.svelte
@@ -1,1042 +1,1042 @@
<script lang="ts">
- import AWC from './../../../../lib/User/BadgeWall/AWC.svelte';
- import { user, type User } from '$lib/Data/AniList/user';
- import type { Badge } from '../../../../graphql/$types';
- import { onDestroy, onMount } from 'svelte';
- import HeadTitle from '$lib/Home/HeadTitle.svelte';
- import { databaseTimeToDate, dateToInputTime, inputTimeToDatabaseTime } from '$lib/Utility/time';
- import proxy from '$lib/Utility/proxy';
- import locale from '$stores/locale';
- import Skeleton from '$lib/Loading/Skeleton.svelte';
- import Message from '$lib/Loading/Message.svelte';
- import Dropdown from '$lib/Layout/Dropdown.svelte';
- import { activityText } from '$lib/Data/AniList/activity';
- import SettingHint from '$lib/Settings/SettingHint.svelte';
- import Popup from '$lib/Layout/Popup.svelte';
- import { page } from '$app/stores';
- import { browser } from '$app/environment';
- import BadgePreview from '$lib/User/BadgeWall/BadgePreview.svelte';
- import authorisedJson from '$lib/Data/Static/authorised.json';
- import identity from '$stores/identity';
- import '$lib/User/BadgeWall/badges.css';
- import Badges from '$lib/User/BadgeWall/Badges.svelte';
- import type { IndexedBadge } from '$lib/User/BadgeWall/badge';
- import { graphql } from '$houdini';
- import type { Preferences } from '../../../../graphql/user/$types';
-
- export let data;
-
- $: ({ BadgeWallUser } = data);
- $: preferences = $BadgeWallUser.fetching
- ? undefined
- : ($BadgeWallUser.data?.User.preferences as Preferences);
-
- $: if (browser && preferences && preferences.badge_wall_css) {
- const sanitise = (css: string) =>
- css
- .replace(/\/\*[\s\S]*?\*\//g, '')
- .replace(/<\/?[^>]+(>|$)/g, '')
- .replace(
- /(expression|javascript|vbscript|onerror|onload|onclick|onmouseover|onmouseout|onmouseup|onmousedown|onkeydown|onkeyup|onkeypress|onblur|onfocus|onsubmit|onreset|onselect|onchange|ondblclick):/gi,
- ''
- )
- .replace(/(behaviour|behavior|moz-binding|content):/gi, '')
- .replace(/\s+/g, ' ')
- .trim();
- const style = document.createElement('style');
-
- style.dataset.badgeWall = 'true';
- style.innerHTML = sanitise(preferences.badge_wall_css);
-
- document.head.appendChild(style);
- }
-
- const updateBadgeQuery = graphql(`
- mutation UpdateBadge(
- $id: Int
- $post: String
- $image: String
- $description: String
- $time: String
- $category: String
- $hidden: Boolean
- $source: String
- $designer: String
- ) {
- updateBadge(
- id: $id
- post: $post
- image: $image
- description: $description
- time: $time
- category: $category
- hidden: $hidden
- source: $source
- designer: $designer
- ) {
- id
-
- badges {
- post
- image
- description
- id
- time
- category
- hidden
- source
- designer
- shadow_hidden
- click_count
- }
- }
- }
- `);
-
- const pruneBadgesQuery = graphql(`
- mutation PruneUserBadges {
- pruneUserBadges {
- id
-
- badges {
- post
- image
- description
- id
- time
- category
- hidden
- source
- designer
- shadow_hidden
- click_count
- }
- }
- }
- `);
-
- const hideCategoryQuery = graphql(`
- mutation HideCategory($category: String) {
- hideBadge(category: $category) {
- id
-
- badges {
- post
- image
- description
- id
- time
- category
- hidden
- source
- designer
- shadow_hidden
- click_count
- }
- }
- }
- `);
-
- const deleteBadgeQuery = graphql(`
- mutation DeleteBadge($id: Int!) {
- deleteBadge(id: $id) {
- id
-
- badges {
- post
- image
- description
- id
- time
- category
- hidden
- source
- designer
- shadow_hidden
- click_count
- }
- }
- }
- `);
-
- const shadowHideBadgeQuery = graphql(`
- mutation ShadowHideBadge($id: Int!, $state: Boolean) {
- shadowHideBadge(id: $id, state: $state) {
- id
-
- badges {
- id
- }
- }
- }
- `);
-
- interface ImportImage {
- link?: string;
- image: string;
- }
-
- let editMode = false;
- let importMode = false;
- let error: null | string;
- let awcPromise: Promise<Response>;
- let confirmDelete = 0;
- let confirmPrune = 0;
- let selectedBadge: IndexedBadge | undefined = undefined;
- let loadError: string | null = null;
- const isId = /^\d+$/.test(data.username);
- let importImages: ImportImage[] | undefined = undefined;
- let importLinks = false;
- let importCategory = '';
- let importReplies = false;
- let badger: Partial<User>;
- let migrateMode = false;
- let hideMode = false;
- const authorised = authorisedJson.includes($identity.id);
- let noticeDismissed = false;
-
- $: categoryFilter = new URLSearchParams($page.url.searchParams).get('category');
-
- type GroupedBadges = { [key: string]: IndexedBadge[] };
-
- const setShadowHide = () =>
- shadowHideBadgeQuery.mutate({
- id: badger.id as number
- });
-
- onMount(async () => {
- if (browser && localStorage.getItem('badgeWallNoticeDismissed')) noticeDismissed = true;
-
- badger = isId
- ? {
- id: parseInt(data.username),
- name: 'User'
- }
- : await user(data.username);
-
- if (!isId && !badger) {
- loadError = 'User not found.';
-
- return;
- }
-
- awcPromise = fetch(proxy(`https://awc.moe/challenger/${badger.name}`));
- });
-
- onDestroy(() => {
- if (browser)
- Array.from(document.head.querySelectorAll('style')).forEach((style) => {
- if (style.dataset.badgeWall) style.remove();
- });
- });
-
- const submitBadge = () => {
- const imageURL = document.querySelector('input[name="image_url"]') as HTMLInputElement;
- const activityURL = document.querySelector('input[name="activity_url"]') as HTMLInputElement;
- const description = document.querySelector('input[name="description"]') as HTMLInputElement;
- const time = document.querySelector('input[type="datetime-local"]') as HTMLInputElement;
- const category = document.querySelector('input[name="category"]') as HTMLInputElement;
- const hidden = document.querySelector('input[name="hidden"]') as HTMLInputElement;
- const source = document.querySelector('input[name="source"]') as HTMLInputElement;
- const designer = document.querySelector('input[name="designer"]') as HTMLInputElement;
-
- if (!imageURL.value) {
- error = 'Image URL cannot be empty.';
-
- return;
- }
-
- if (
- !imageURL.value.startsWith('http') ||
- (activityURL.value.length > 0 && !activityURL.value.startsWith('http'))
- ) {
- error = 'URLs must start with http or https.';
-
- return;
- }
-
- updateBadgeQuery
- .mutate({
- id: selectedBadge?.id,
- image: imageURL.value,
- post: activityURL.value || '#',
- description: description.value,
- category: category.value,
- time: time.valueAsDate ? inputTimeToDatabaseTime(time.valueAsDate) : undefined,
- hidden: hidden.value === 'Hidden',
- source: source.value,
- designer: designer.value
- })
- .then(() => {
- error = null;
- imageURL.value = '';
- activityURL.value = '';
- description.value = '';
- category.value = '';
- hidden.value = 'Shown';
- selectedBadge = undefined;
- source.value = '';
- designer.value = '';
- });
- };
-
- const removeAllBadges = () => {
- if (confirmPrune === 2) {
- confirmPrune = 0;
- } else if (confirmPrune === 0) {
- confirmPrune = 1;
-
- return;
- } else {
- confirmPrune = 2;
-
- return;
- }
-
- selectedBadge = undefined;
-
- pruneBadgesQuery.mutate(null).then();
- };
-
- const removeBadge = (badge: Badge) => {
- if (!badge.id) return;
-
- if (confirmDelete === badge.id * 2) {
- confirmDelete = 0;
- } else if (confirmDelete / 4 === badge.id) {
- confirmDelete = badge.id * 2;
-
- return;
- } else {
- confirmDelete = badge.id * 2;
-
- return;
- }
-
- selectedBadge = undefined;
-
- deleteBadgeQuery
- .mutate({
- id: badge.id
- })
- .then();
- };
-
- const groupBadges = (badges: IndexedBadge[]) => {
- const groupedBadges: GroupedBadges = {};
-
- badges.forEach((badge) => {
- if (!badge.category) badge.category = 'Uncategorised';
-
- if (!groupedBadges[badge.category]) groupedBadges[badge.category] = [];
-
- groupedBadges[badge.category].push(badge);
- });
-
- Object.entries(groupedBadges).forEach(([_category, badges]) => {
- badges.forEach((badge, index) => {
- badge.index = index;
- });
- });
-
- return Object.entries(groupedBadges)
- .sort((a, b) => a[1].length - b[1].length)
- .sort((a, b) => {
- const pinnedCategories =
- preferences && preferences.pinned_badge_wall_categories
- ? preferences.pinned_badge_wall_categories
- : ([] as string[]);
- const aIndex = pinnedCategories.indexOf(a[0]);
- const bIndex = pinnedCategories.indexOf(b[0]);
-
- if (aIndex === -1 && bIndex === -1) return 0;
- if (aIndex === -1) return 1;
- if (bIndex === -1) return -1;
-
- return aIndex - bIndex;
- })
- .reduce((set: GroupedBadges, [key, value]) => {
- set[key] = value;
-
- return set;
- }, {});
- };
-
- const parsePost = async () => {
- if (importImages && importImages.length > 0) importImages = undefined;
-
- const link = (document.querySelector('#import_activity_url') as HTMLInputElement).value;
- const type = link.replace(/.*\/(activity|thread)\/(\d+).*/, '$1');
- const id = link.replace(/.*\/(activity|thread)\/(\d+).*/, '$2');
-
- if (type !== 'activity') return null;
-
- let text = await activityText(parseInt(id), importReplies);
-
- const images: ImportImage[] = [];
-
- if (importLinks) {
- Array.from(new DOMParser().parseFromString(text, 'text/html').querySelectorAll('a')).forEach(
- (a) => {
- const anchor = a as HTMLAnchorElement;
-
- if (anchor.querySelector('img')) {
- images.push({
- link: anchor.href,
- image: (anchor.querySelector('img') as HTMLImageElement).src
- });
- }
- }
- );
-
- text = text.replace(/<a.*?>.*?<img.*?>.*?<\/a>/g, '');
-
- Array.from(
- new DOMParser().parseFromString(text, 'text/html').querySelectorAll('img')
- ).forEach((img) => {
- const image = img as HTMLImageElement;
-
- images.push({
- image: image.src
- });
- });
- } else {
- Array.from(
- new DOMParser().parseFromString(text, 'text/html').querySelectorAll('img')
- ).forEach((img) => {
- const image = img as HTMLImageElement;
-
- images.push({
- image: image.src
- });
- });
- }
-
- importImages = images;
- };
-
- const importBadges = () =>
- fetch(
- `/api/badges?import=true
+ import AWC from './../../../../lib/User/BadgeWall/AWC.svelte';
+ import { user, type User } from '$lib/Data/AniList/user';
+ import type { Badge } from '../../../../graphql/$types';
+ import { onDestroy, onMount } from 'svelte';
+ import HeadTitle from '$lib/Home/HeadTitle.svelte';
+ import { databaseTimeToDate, dateToInputTime, inputTimeToDatabaseTime } from '$lib/Utility/time';
+ import proxy from '$lib/Utility/proxy';
+ import locale from '$stores/locale';
+ import Skeleton from '$lib/Loading/Skeleton.svelte';
+ import Message from '$lib/Loading/Message.svelte';
+ import Dropdown from '$lib/Layout/Dropdown.svelte';
+ import { activityText } from '$lib/Data/AniList/activity';
+ import SettingHint from '$lib/Settings/SettingHint.svelte';
+ import Popup from '$lib/Layout/Popup.svelte';
+ import { page } from '$app/stores';
+ import { browser } from '$app/environment';
+ import BadgePreview from '$lib/User/BadgeWall/BadgePreview.svelte';
+ import authorisedJson from '$lib/Data/Static/authorised.json';
+ import identity from '$stores/identity';
+ import '$lib/User/BadgeWall/badges.css';
+ import Badges from '$lib/User/BadgeWall/Badges.svelte';
+ import type { IndexedBadge } from '$lib/User/BadgeWall/badge';
+ import { graphql } from '$houdini';
+ import type { Preferences } from '../../../../graphql/user/$types';
+
+ export let data;
+
+ $: ({ BadgeWallUser } = data);
+ $: preferences = $BadgeWallUser.fetching
+ ? undefined
+ : ($BadgeWallUser.data?.User.preferences as Preferences);
+
+ $: if (browser && preferences && preferences.badge_wall_css) {
+ const sanitise = (css: string) =>
+ css
+ .replace(/\/\*[\s\S]*?\*\//g, '')
+ .replace(/<\/?[^>]+(>|$)/g, '')
+ .replace(
+ /(expression|javascript|vbscript|onerror|onload|onclick|onmouseover|onmouseout|onmouseup|onmousedown|onkeydown|onkeyup|onkeypress|onblur|onfocus|onsubmit|onreset|onselect|onchange|ondblclick):/gi,
+ ''
+ )
+ .replace(/(behaviour|behavior|moz-binding|content):/gi, '')
+ .replace(/\s+/g, ' ')
+ .trim();
+ const style = document.createElement('style');
+
+ style.dataset.badgeWall = 'true';
+ style.innerHTML = sanitise(preferences.badge_wall_css);
+
+ document.head.appendChild(style);
+ }
+
+ const updateBadgeQuery = graphql(`
+ mutation UpdateBadge(
+ $id: Int
+ $post: String
+ $image: String
+ $description: String
+ $time: String
+ $category: String
+ $hidden: Boolean
+ $source: String
+ $designer: String
+ ) {
+ updateBadge(
+ id: $id
+ post: $post
+ image: $image
+ description: $description
+ time: $time
+ category: $category
+ hidden: $hidden
+ source: $source
+ designer: $designer
+ ) {
+ id
+
+ badges {
+ post
+ image
+ description
+ id
+ time
+ category
+ hidden
+ source
+ designer
+ shadow_hidden
+ click_count
+ }
+ }
+ }
+ `);
+
+ const pruneBadgesQuery = graphql(`
+ mutation PruneUserBadges {
+ pruneUserBadges {
+ id
+
+ badges {
+ post
+ image
+ description
+ id
+ time
+ category
+ hidden
+ source
+ designer
+ shadow_hidden
+ click_count
+ }
+ }
+ }
+ `);
+
+ const hideCategoryQuery = graphql(`
+ mutation HideCategory($category: String) {
+ hideBadge(category: $category) {
+ id
+
+ badges {
+ post
+ image
+ description
+ id
+ time
+ category
+ hidden
+ source
+ designer
+ shadow_hidden
+ click_count
+ }
+ }
+ }
+ `);
+
+ const deleteBadgeQuery = graphql(`
+ mutation DeleteBadge($id: Int!) {
+ deleteBadge(id: $id) {
+ id
+
+ badges {
+ post
+ image
+ description
+ id
+ time
+ category
+ hidden
+ source
+ designer
+ shadow_hidden
+ click_count
+ }
+ }
+ }
+ `);
+
+ const shadowHideBadgeQuery = graphql(`
+ mutation ShadowHideBadge($id: Int!, $state: Boolean) {
+ shadowHideBadge(id: $id, state: $state) {
+ id
+
+ badges {
+ id
+ }
+ }
+ }
+ `);
+
+ interface ImportImage {
+ link?: string;
+ image: string;
+ }
+
+ let editMode = false;
+ let importMode = false;
+ let error: null | string;
+ let awcPromise: Promise<Response>;
+ let confirmDelete = 0;
+ let confirmPrune = 0;
+ let selectedBadge: IndexedBadge | undefined = undefined;
+ let loadError: string | null = null;
+ const isId = /^\d+$/.test(data.username);
+ let importImages: ImportImage[] | undefined = undefined;
+ let importLinks = false;
+ let importCategory = '';
+ let importReplies = false;
+ let badger: Partial<User>;
+ let migrateMode = false;
+ let hideMode = false;
+ const authorised = authorisedJson.includes($identity.id);
+ let noticeDismissed = false;
+
+ $: categoryFilter = new URLSearchParams($page.url.searchParams).get('category');
+
+ type GroupedBadges = { [key: string]: IndexedBadge[] };
+
+ const setShadowHide = () =>
+ shadowHideBadgeQuery.mutate({
+ id: badger.id as number
+ });
+
+ onMount(async () => {
+ if (browser && localStorage.getItem('badgeWallNoticeDismissed')) noticeDismissed = true;
+
+ badger = isId
+ ? {
+ id: parseInt(data.username),
+ name: 'User'
+ }
+ : await user(data.username);
+
+ if (!isId && !badger) {
+ loadError = 'User not found.';
+
+ return;
+ }
+
+ awcPromise = fetch(proxy(`https://awc.moe/challenger/${badger.name}`));
+ });
+
+ onDestroy(() => {
+ if (browser)
+ Array.from(document.head.querySelectorAll('style')).forEach((style) => {
+ if (style.dataset.badgeWall) style.remove();
+ });
+ });
+
+ const submitBadge = () => {
+ const imageURL = document.querySelector('input[name="image_url"]') as HTMLInputElement;
+ const activityURL = document.querySelector('input[name="activity_url"]') as HTMLInputElement;
+ const description = document.querySelector('input[name="description"]') as HTMLInputElement;
+ const time = document.querySelector('input[type="datetime-local"]') as HTMLInputElement;
+ const category = document.querySelector('input[name="category"]') as HTMLInputElement;
+ const hidden = document.querySelector('input[name="hidden"]') as HTMLInputElement;
+ const source = document.querySelector('input[name="source"]') as HTMLInputElement;
+ const designer = document.querySelector('input[name="designer"]') as HTMLInputElement;
+
+ if (!imageURL.value) {
+ error = 'Image URL cannot be empty.';
+
+ return;
+ }
+
+ if (
+ !imageURL.value.startsWith('http') ||
+ (activityURL.value.length > 0 && !activityURL.value.startsWith('http'))
+ ) {
+ error = 'URLs must start with http or https.';
+
+ return;
+ }
+
+ updateBadgeQuery
+ .mutate({
+ id: selectedBadge?.id,
+ image: imageURL.value,
+ post: activityURL.value || '#',
+ description: description.value,
+ category: category.value,
+ time: time.valueAsDate ? inputTimeToDatabaseTime(time.valueAsDate) : undefined,
+ hidden: hidden.value === 'Hidden',
+ source: source.value,
+ designer: designer.value
+ })
+ .then(() => {
+ error = null;
+ imageURL.value = '';
+ activityURL.value = '';
+ description.value = '';
+ category.value = '';
+ hidden.value = 'Shown';
+ selectedBadge = undefined;
+ source.value = '';
+ designer.value = '';
+ });
+ };
+
+ const removeAllBadges = () => {
+ if (confirmPrune === 2) {
+ confirmPrune = 0;
+ } else if (confirmPrune === 0) {
+ confirmPrune = 1;
+
+ return;
+ } else {
+ confirmPrune = 2;
+
+ return;
+ }
+
+ selectedBadge = undefined;
+
+ pruneBadgesQuery.mutate(null).then();
+ };
+
+ const removeBadge = (badge: Badge) => {
+ if (!badge.id) return;
+
+ if (confirmDelete === badge.id * 2) {
+ confirmDelete = 0;
+ } else if (confirmDelete / 4 === badge.id) {
+ confirmDelete = badge.id * 2;
+
+ return;
+ } else {
+ confirmDelete = badge.id * 2;
+
+ return;
+ }
+
+ selectedBadge = undefined;
+
+ deleteBadgeQuery
+ .mutate({
+ id: badge.id
+ })
+ .then();
+ };
+
+ const groupBadges = (badges: IndexedBadge[]) => {
+ const groupedBadges: GroupedBadges = {};
+
+ badges.forEach((badge) => {
+ if (!badge.category) badge.category = 'Uncategorised';
+
+ if (!groupedBadges[badge.category]) groupedBadges[badge.category] = [];
+
+ groupedBadges[badge.category].push(badge);
+ });
+
+ Object.entries(groupedBadges).forEach(([_category, badges]) => {
+ badges.forEach((badge, index) => {
+ badge.index = index;
+ });
+ });
+
+ return Object.entries(groupedBadges)
+ .sort((a, b) => a[1].length - b[1].length)
+ .sort((a, b) => {
+ const pinnedCategories =
+ preferences && preferences.pinned_badge_wall_categories
+ ? preferences.pinned_badge_wall_categories
+ : ([] as string[]);
+ const aIndex = pinnedCategories.indexOf(a[0]);
+ const bIndex = pinnedCategories.indexOf(b[0]);
+
+ if (aIndex === -1 && bIndex === -1) return 0;
+ if (aIndex === -1) return 1;
+ if (bIndex === -1) return -1;
+
+ return aIndex - bIndex;
+ })
+ .reduce((set: GroupedBadges, [key, value]) => {
+ set[key] = value;
+
+ return set;
+ }, {});
+ };
+
+ const parsePost = async () => {
+ if (importImages && importImages.length > 0) importImages = undefined;
+
+ const link = (document.querySelector('#import_activity_url') as HTMLInputElement).value;
+ const type = link.replace(/.*\/(activity|thread)\/(\d+).*/, '$1');
+ const id = link.replace(/.*\/(activity|thread)\/(\d+).*/, '$2');
+
+ if (type !== 'activity') return null;
+
+ let text = await activityText(parseInt(id), importReplies);
+
+ const images: ImportImage[] = [];
+
+ if (importLinks) {
+ Array.from(new DOMParser().parseFromString(text, 'text/html').querySelectorAll('a')).forEach(
+ (a) => {
+ const anchor = a as HTMLAnchorElement;
+
+ if (anchor.querySelector('img')) {
+ images.push({
+ link: anchor.href,
+ image: (anchor.querySelector('img') as HTMLImageElement).src
+ });
+ }
+ }
+ );
+
+ text = text.replace(/<a.*?>.*?<img.*?>.*?<\/a>/g, '');
+
+ Array.from(
+ new DOMParser().parseFromString(text, 'text/html').querySelectorAll('img')
+ ).forEach((img) => {
+ const image = img as HTMLImageElement;
+
+ images.push({
+ image: image.src
+ });
+ });
+ } else {
+ Array.from(
+ new DOMParser().parseFromString(text, 'text/html').querySelectorAll('img')
+ ).forEach((img) => {
+ const image = img as HTMLImageElement;
+
+ images.push({
+ image: image.src
+ });
+ });
+ }
+
+ importImages = images;
+ };
+
+ const importBadges = () =>
+ fetch(
+ `/api/badges?import=true
${importCategory.length > 0 ? `&category=${encodeURIComponent(importCategory)}` : ''}
`,
- {
- method: 'PUT',
- headers: {
- 'Content-Type': 'application/json'
- },
- body: JSON.stringify(
- importImages?.map((image) => ({
- image: image.image,
- post: image.link || '#',
- category: importCategory
- }))
- )
- }
- ).then(() => {
- importMode = false;
- importImages = undefined;
- });
-
- const migrateCategory = () => {
- fetch(
- `/api/badges?migrate=true&original=${encodeURIComponent(
- (document.querySelector('#migrate_original') as HTMLInputElement).value
- )}&new=${encodeURIComponent(
- (document.querySelector('#migrate_new') as HTMLInputElement).value
- )}`,
- {
- method: 'PUT'
- }
- ).then(() => (migrateMode = false));
- };
-
- const hideCategory = () => {
- hideCategoryQuery
- .mutate({
- category: (document.querySelector('#category_hide') as HTMLInputElement).value
- })
- .then(() => (hideMode = false));
- };
-
- const removeHiddenBadges = (isOwner: boolean, badges: IndexedBadge[]) =>
- isOwner || authorised ? badges : badges.filter((b) => !b.hidden && !b.shadow_hidden);
-
- const setAdjacentCursor = (badges: IndexedBadge[], direction: number) => {
- const currentCategory = selectedBadge?.category || 'Uncategorised';
- const currentBadge = selectedBadge?.index;
- const categoryBadges = groupBadges(badges)[currentCategory];
-
- if (!currentCategory || currentBadge === undefined) return;
-
- let previousBadge = categoryBadges[currentBadge + direction];
-
- while (previousBadge && (previousBadge.hidden || previousBadge.shadow_hidden))
- previousBadge = categoryBadges[previousBadge.index + direction];
-
- if (previousBadge) selectedBadge = previousBadge;
- };
-
- const adjacentBadgeExists = (
- selectedBadge: IndexedBadge | undefined,
- badges: IndexedBadge[],
- direction: number
- ) => {
- const currentCategory = selectedBadge?.category || 'Uncategorised';
- const currentBadge = selectedBadge?.index;
- const categoryBadges = groupBadges(badges)[currentCategory];
-
- if (!currentCategory || currentBadge === undefined || !categoryBadges) return;
-
- let previousBadge = categoryBadges[currentBadge + direction];
-
- while (previousBadge && (previousBadge.hidden || previousBadge.shadow_hidden))
- previousBadge = categoryBadges[previousBadge.index + direction];
-
- return previousBadge;
- };
-
- const castAsStringArray = (array: any[]) => array as string[];
-
- const castBadgesToIndexedBadges = (array: any[]) => array as IndexedBadge[];
-
- const shadowHideBadge = () => {
- if (!selectedBadge && !authorised) return;
-
- shadowHideBadgeQuery
- .mutate({
- id: badger.id as number,
- state: selectedBadge?.shadow_hidden as boolean
- })
- .then();
- };
+ {
+ method: 'PUT',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify(
+ importImages?.map((image) => ({
+ image: image.image,
+ post: image.link || '#',
+ category: importCategory
+ }))
+ )
+ }
+ ).then(() => {
+ importMode = false;
+ importImages = undefined;
+ });
+
+ const migrateCategory = () => {
+ fetch(
+ `/api/badges?migrate=true&original=${encodeURIComponent(
+ (document.querySelector('#migrate_original') as HTMLInputElement).value
+ )}&new=${encodeURIComponent(
+ (document.querySelector('#migrate_new') as HTMLInputElement).value
+ )}`,
+ {
+ method: 'PUT'
+ }
+ ).then(() => (migrateMode = false));
+ };
+
+ const hideCategory = () => {
+ hideCategoryQuery
+ .mutate({
+ category: (document.querySelector('#category_hide') as HTMLInputElement).value
+ })
+ .then(() => (hideMode = false));
+ };
+
+ const removeHiddenBadges = (isOwner: boolean, badges: IndexedBadge[]) =>
+ isOwner || authorised ? badges : badges.filter((b) => !b.hidden && !b.shadow_hidden);
+
+ const setAdjacentCursor = (badges: IndexedBadge[], direction: number) => {
+ const currentCategory = selectedBadge?.category || 'Uncategorised';
+ const currentBadge = selectedBadge?.index;
+ const categoryBadges = groupBadges(badges)[currentCategory];
+
+ if (!currentCategory || currentBadge === undefined) return;
+
+ let previousBadge = categoryBadges[currentBadge + direction];
+
+ while (previousBadge && (previousBadge.hidden || previousBadge.shadow_hidden))
+ previousBadge = categoryBadges[previousBadge.index + direction];
+
+ if (previousBadge) selectedBadge = previousBadge;
+ };
+
+ const adjacentBadgeExists = (
+ selectedBadge: IndexedBadge | undefined,
+ badges: IndexedBadge[],
+ direction: number
+ ) => {
+ const currentCategory = selectedBadge?.category || 'Uncategorised';
+ const currentBadge = selectedBadge?.index;
+ const categoryBadges = groupBadges(badges)[currentCategory];
+
+ if (!currentCategory || currentBadge === undefined || !categoryBadges) return;
+
+ let previousBadge = categoryBadges[currentBadge + direction];
+
+ while (previousBadge && (previousBadge.hidden || previousBadge.shadow_hidden))
+ previousBadge = categoryBadges[previousBadge.index + direction];
+
+ return previousBadge;
+ };
+
+ const castAsStringArray = (array: any[]) => array as string[];
+
+ const castBadgesToIndexedBadges = (array: any[]) => array as IndexedBadge[];
+
+ const shadowHideBadge = () => {
+ if (!selectedBadge && !authorised) return;
+
+ shadowHideBadgeQuery
+ .mutate({
+ id: badger.id as number,
+ state: selectedBadge?.shadow_hidden as boolean
+ })
+ .then();
+ };
</script>
<HeadTitle route={`${data.username}'s Badge Wall`} path={`/user/${data.username}`} />
{#if loadError}
- <Popup fullscreen locked>
- {loadError}
- </Popup>
+ <Popup fullscreen locked>
+ {loadError}
+ </Popup>
{:else}
- {@const isOwner = $identity && (isId ? $identity.id : $identity.name) === data.username}
-
- {#if $BadgeWallUser.fetching || !$BadgeWallUser.data}
- <Message message="Loading badges ..." />
-
- <Skeleton grid={true} count={100} width="150px" height="170px" />
- {:else}
- {@const ungroupedBadges = castBadgesToIndexedBadges($BadgeWallUser.data.User.badges)}
- {@const isBadgeSelected =
- selectedBadge &&
- selectedBadge !== undefined &&
- selectedBadge.image &&
- selectedBadge.image !== undefined &&
- !editMode}
-
- <div id="badges">
- {#if preferences && !preferences.hide_awc_badges}
- <AWC {awcPromise} {categoryFilter} {isOwner} {preferences} />
- {/if}
-
- {#if ungroupedBadges === null}
- <Message message="Loading badges ..." />
-
- <Skeleton grid={true} count={10} width="150px" height="170px" />
- {:else}
- {@const groupedBadges = Object.entries(
- groupBadges(removeHiddenBadges(isOwner, ungroupedBadges))
- )}
-
- {#if isOwner || authorised}
- {@const shadowHiddenCount = ungroupedBadges.filter((badge) => badge.shadow_hidden).length}
- {@const shadowHidden = shadowHiddenCount > 0}
-
- {#if shadowHidden}
- <div class="card">
- <b>Notice:</b> The Badge Wall overseer system has detected badges containing
- AI-generated material on your wall. {shadowHiddenCount} of your badges have been shadow
- hidden.
- <p />
- You may use the "Un-shadow Hide Badges" button to unhide these badges, from where you will
- be required to use the hide feature to hide these badges from the public, while allowing
- them to stay visible to you as the account holder.
- </div>
- {:else if !noticeDismissed}
- <div class="card">
- <b>Notice:</b> AniList has begun purging outbound links which contain AI-generated
- material, this includes Badge Wall. If you have collected badges with AI-generated
- elements, kindly use the hide feature to hide these badges from the public, while
- allowing them to stay visible to you as the account holder.
- <p />
- Failure to comply with this request at your earliest convenience will result in the hiding
- of all badges from your Badge Wall.
- <p />
- <button
- on:click={() => {
- noticeDismissed = true;
-
- localStorage.setItem('badgeWallNoticeDismissed', 'true');
- }}
- >
- Dismiss
- </button>
- </div>
- {/if}
-
- <p />
-
- <div class="card">
- {#if authorised}
- <button on:click={setShadowHide}>Shadow Hide Badges</button>
- {/if}
-
- {#if isOwner && authorised}
- <span style="margin: 0 0.625rem;">•</span>
- {/if}
-
- {#if isOwner}
- <button
- on:click={() => {
- selectedBadge = undefined;
- editMode = !editMode;
- }}
- >
- {editMode
- ? $locale().user.badges.editMode.disable
- : $locale().user.badges.editMode.enable}
- </button>
- <span style="margin: 0 0.625rem;">•</span>
- <button
- on:click={() => {
- selectedBadge = undefined;
- importMode = !importMode;
- }}
- >
- {importMode
- ? $locale().user.badges.importMode.disable
- : $locale().user.badges.importMode.enable}
- </button>
- <span style="margin: 0 0.625rem;">•</span>
- <button
- on:click={() => {
- selectedBadge = undefined;
- migrateMode = !migrateMode;
- }}
- >
- Migrate Category
- </button>
- <span style="margin: 0 0.625rem;">•</span>
- <button
- on:click={() => {
- selectedBadge = undefined;
- hideMode = !hideMode;
- }}
- >
- Hide Category
- </button>
- <!-- <!-- <span style="margin: 0 0.625rem;">•</span> -->
- <!-- <button on:click={() => exportBadges(groupedBadges)}>Export Badges</button> -->
-
- {#if shadowHidden}
- <span style="margin: 0 0.625rem;">•</span>
- <button on:click={setShadowHide}>Un-shadow Hide Badges</button>
- {/if}
-
- {#if editMode && isOwner}
- {@const groups = groupedBadges
- .map((group) => group[0])
- .filter((group) => group !== 'Uncategorised')}
- {@const designers = castAsStringArray([
- ...new Set(
- ungroupedBadges
- .map((badge) => badge.designer)
- .filter((designer) => designer !== undefined && designer !== null)
- .filter(
- (designer, index, array) =>
- array.indexOf(designer) === index && !array.includes(`@${designer}`)
- )
- )
- ])}
-
- <p />
-
- {#if error}
- <p style="color: red;">{error}</p>
- {/if}
-
- <input
- type="text"
- placeholder={$locale().user.badges.editMode.imageURL}
- name="image_url"
- minlength="1"
- maxlength="1000"
- size="15"
- value={selectedBadge ? selectedBadge.image : ''}
- />
- <input
- type="text"
- placeholder={$locale().user.badges.editMode.activityURL}
- name="activity_url"
- minlength="1"
- maxlength="1000"
- size="15"
- value={selectedBadge
- ? selectedBadge.post === '#'
- ? ''
- : selectedBadge.post
- : ''}
- />
- <input
- type="text"
- placeholder={$locale().user.badges.editMode.description}
- name="description"
- minlength="1"
- maxlength="1000"
- size="15"
- value={selectedBadge ? selectedBadge.description : ''}
- />
- <Dropdown
- items={groups.map((group) => ({
- name: group,
- url: '#',
- onClick: () => {
- const category = document.querySelector('input[name="category"]');
-
- if (category instanceof HTMLInputElement) category.value = group;
- }
- }))}
- header={false}
- center={false}
- >
- <span slot="title">
- <input
- type="text"
- placeholder={$locale().user.badges.editMode.category}
- name="category"
- minlength="1"
- maxlength="1000"
- size="15"
- value={selectedBadge
- ? selectedBadge.category === 'Uncategorised'
- ? ''
- : selectedBadge.category
- : ''}
- list="categories"
- />
- </span>
- </Dropdown>
- <span style="float: right;">
- <input
- type="datetime-local"
- value={selectedBadge && selectedBadge.time
- ? dateToInputTime(databaseTimeToDate(selectedBadge.time))
- : ''}
- />
- <small>Must be full date and time, defaults to now if any fields empty</small>
- </span>
-
- <p />
-
- <div class="edit-row-2">
- <input
- type="text"
- placeholder={$locale().user.badges.editMode.source}
- name="source"
- minlength="1"
- maxlength="1000"
- size="16"
- value={selectedBadge ? selectedBadge.source : ''}
- />
- <Dropdown
- items={designers.map((designer) => ({
- name: designer,
- url: '#',
- onClick: () => {
- const designerField = document.querySelector('input[name="designer"]');
-
- if (designerField instanceof HTMLInputElement)
- designerField.value = designer;
- }
- }))}
- header={false}
- center={false}
- >
- <span slot="title">
- <input
- type="text"
- placeholder={$locale().user.badges.editMode.designer}
- name="designer"
- minlength="1"
- maxlength="1000"
- size="17"
- value={selectedBadge ? selectedBadge.designer : ''}
- />
- </span>
- </Dropdown>
- <Dropdown
- items={[false, true].map((hidden) => ({
- name: hidden ? 'Hidden' : 'Shown',
- url: '#',
- onClick: () => {
- const hiddenInput = document.querySelector('input[name="hidden"]');
-
- if (hiddenInput instanceof HTMLInputElement)
- hiddenInput.value = hidden ? 'Hidden' : 'Shown';
- }
- }))}
- header={false}
- center={false}
- >
- <span slot="title">
- <input
- type="text"
- placeholder="Shown"
- name="hidden"
- minlength="1"
- maxlength="1000"
- size="15"
- value={selectedBadge
- ? selectedBadge.hidden
- ? 'Hidden'
- : 'Shown'
- : 'Shown'}
- />
- </span>
- </Dropdown>
- <button class="button-lined" on:click={submitBadge}
- >{selectedBadge
- ? $locale().user.badges.editMode.update
- : $locale().user.badges.editMode.add}</button
- >
- {#if selectedBadge}
- {$locale().user.badges.editMode.or}
- <button
- class="button-lined"
- on:click={() => {
- if (selectedBadge) removeBadge(selectedBadge);
- }}>{$locale().user.badges.editMode.delete}</button
- >
- {/if}
- </div>
- {/if}
- {/if}
- </div>
- {/if}
-
- <p />
-
- <Badges
- {ungroupedBadges}
- {groupedBadges}
- {categoryFilter}
- {editMode}
- {preferences}
- bind:selectedBadge
- />
- {/if}
- </div>
-
- {#if isBadgeSelected}
- <!-- {@const anyAdjacentBadgeExists =
+ {@const isOwner = $identity && (isId ? $identity.id : $identity.name) === data.username}
+
+ {#if $BadgeWallUser.fetching || !$BadgeWallUser.data}
+ <Message message="Loading badges ..." />
+
+ <Skeleton grid={true} count={100} width="150px" height="170px" />
+ {:else}
+ {@const ungroupedBadges = castBadgesToIndexedBadges($BadgeWallUser.data.User.badges)}
+ {@const isBadgeSelected =
+ selectedBadge &&
+ selectedBadge !== undefined &&
+ selectedBadge.image &&
+ selectedBadge.image !== undefined &&
+ !editMode}
+
+ <div id="badges">
+ {#if preferences && !preferences.hide_awc_badges}
+ <AWC {awcPromise} {categoryFilter} {isOwner} {preferences} />
+ {/if}
+
+ {#if ungroupedBadges === null}
+ <Message message="Loading badges ..." />
+
+ <Skeleton grid={true} count={10} width="150px" height="170px" />
+ {:else}
+ {@const groupedBadges = Object.entries(
+ groupBadges(removeHiddenBadges(isOwner, ungroupedBadges))
+ )}
+
+ {#if isOwner || authorised}
+ {@const shadowHiddenCount = ungroupedBadges.filter((badge) => badge.shadow_hidden).length}
+ {@const shadowHidden = shadowHiddenCount > 0}
+
+ {#if shadowHidden}
+ <div class="card">
+ <b>Notice:</b> The Badge Wall overseer system has detected badges containing
+ AI-generated material on your wall. {shadowHiddenCount} of your badges have been shadow
+ hidden.
+ <p />
+ You may use the "Un-shadow Hide Badges" button to unhide these badges, from where you will
+ be required to use the hide feature to hide these badges from the public, while allowing
+ them to stay visible to you as the account holder.
+ </div>
+ {:else if !noticeDismissed}
+ <div class="card">
+ <b>Notice:</b> AniList has begun purging outbound links which contain AI-generated
+ material, this includes Badge Wall. If you have collected badges with AI-generated
+ elements, kindly use the hide feature to hide these badges from the public, while
+ allowing them to stay visible to you as the account holder.
+ <p />
+ Failure to comply with this request at your earliest convenience will result in the hiding
+ of all badges from your Badge Wall.
+ <p />
+ <button
+ on:click={() => {
+ noticeDismissed = true;
+
+ localStorage.setItem('badgeWallNoticeDismissed', 'true');
+ }}
+ >
+ Dismiss
+ </button>
+ </div>
+ {/if}
+
+ <p />
+
+ <div class="card">
+ {#if authorised}
+ <button on:click={setShadowHide}>Shadow Hide Badges</button>
+ {/if}
+
+ {#if isOwner && authorised}
+ <span style="margin: 0 0.625rem;">•</span>
+ {/if}
+
+ {#if isOwner}
+ <button
+ on:click={() => {
+ selectedBadge = undefined;
+ editMode = !editMode;
+ }}
+ >
+ {editMode
+ ? $locale().user.badges.editMode.disable
+ : $locale().user.badges.editMode.enable}
+ </button>
+ <span style="margin: 0 0.625rem;">•</span>
+ <button
+ on:click={() => {
+ selectedBadge = undefined;
+ importMode = !importMode;
+ }}
+ >
+ {importMode
+ ? $locale().user.badges.importMode.disable
+ : $locale().user.badges.importMode.enable}
+ </button>
+ <span style="margin: 0 0.625rem;">•</span>
+ <button
+ on:click={() => {
+ selectedBadge = undefined;
+ migrateMode = !migrateMode;
+ }}
+ >
+ Migrate Category
+ </button>
+ <span style="margin: 0 0.625rem;">•</span>
+ <button
+ on:click={() => {
+ selectedBadge = undefined;
+ hideMode = !hideMode;
+ }}
+ >
+ Hide Category
+ </button>
+ <!-- <!-- <span style="margin: 0 0.625rem;">•</span> -->
+ <!-- <button on:click={() => exportBadges(groupedBadges)}>Export Badges</button> -->
+
+ {#if shadowHidden}
+ <span style="margin: 0 0.625rem;">•</span>
+ <button on:click={setShadowHide}>Un-shadow Hide Badges</button>
+ {/if}
+
+ {#if editMode && isOwner}
+ {@const groups = groupedBadges
+ .map((group) => group[0])
+ .filter((group) => group !== 'Uncategorised')}
+ {@const designers = castAsStringArray([
+ ...new Set(
+ ungroupedBadges
+ .map((badge) => badge.designer)
+ .filter((designer) => designer !== undefined && designer !== null)
+ .filter(
+ (designer, index, array) =>
+ array.indexOf(designer) === index && !array.includes(`@${designer}`)
+ )
+ )
+ ])}
+
+ <p />
+
+ {#if error}
+ <p style="color: red;">{error}</p>
+ {/if}
+
+ <input
+ type="text"
+ placeholder={$locale().user.badges.editMode.imageURL}
+ name="image_url"
+ minlength="1"
+ maxlength="1000"
+ size="15"
+ value={selectedBadge ? selectedBadge.image : ''}
+ />
+ <input
+ type="text"
+ placeholder={$locale().user.badges.editMode.activityURL}
+ name="activity_url"
+ minlength="1"
+ maxlength="1000"
+ size="15"
+ value={selectedBadge
+ ? selectedBadge.post === '#'
+ ? ''
+ : selectedBadge.post
+ : ''}
+ />
+ <input
+ type="text"
+ placeholder={$locale().user.badges.editMode.description}
+ name="description"
+ minlength="1"
+ maxlength="1000"
+ size="15"
+ value={selectedBadge ? selectedBadge.description : ''}
+ />
+ <Dropdown
+ items={groups.map((group) => ({
+ name: group,
+ url: '#',
+ onClick: () => {
+ const category = document.querySelector('input[name="category"]');
+
+ if (category instanceof HTMLInputElement) category.value = group;
+ }
+ }))}
+ header={false}
+ center={false}
+ >
+ <span slot="title">
+ <input
+ type="text"
+ placeholder={$locale().user.badges.editMode.category}
+ name="category"
+ minlength="1"
+ maxlength="1000"
+ size="15"
+ value={selectedBadge
+ ? selectedBadge.category === 'Uncategorised'
+ ? ''
+ : selectedBadge.category
+ : ''}
+ list="categories"
+ />
+ </span>
+ </Dropdown>
+ <span style="float: right;">
+ <input
+ type="datetime-local"
+ value={selectedBadge && selectedBadge.time
+ ? dateToInputTime(databaseTimeToDate(selectedBadge.time))
+ : ''}
+ />
+ <small>Must be full date and time, defaults to now if any fields empty</small>
+ </span>
+
+ <p />
+
+ <div class="edit-row-2">
+ <input
+ type="text"
+ placeholder={$locale().user.badges.editMode.source}
+ name="source"
+ minlength="1"
+ maxlength="1000"
+ size="16"
+ value={selectedBadge ? selectedBadge.source : ''}
+ />
+ <Dropdown
+ items={designers.map((designer) => ({
+ name: designer,
+ url: '#',
+ onClick: () => {
+ const designerField = document.querySelector('input[name="designer"]');
+
+ if (designerField instanceof HTMLInputElement)
+ designerField.value = designer;
+ }
+ }))}
+ header={false}
+ center={false}
+ >
+ <span slot="title">
+ <input
+ type="text"
+ placeholder={$locale().user.badges.editMode.designer}
+ name="designer"
+ minlength="1"
+ maxlength="1000"
+ size="17"
+ value={selectedBadge ? selectedBadge.designer : ''}
+ />
+ </span>
+ </Dropdown>
+ <Dropdown
+ items={[false, true].map((hidden) => ({
+ name: hidden ? 'Hidden' : 'Shown',
+ url: '#',
+ onClick: () => {
+ const hiddenInput = document.querySelector('input[name="hidden"]');
+
+ if (hiddenInput instanceof HTMLInputElement)
+ hiddenInput.value = hidden ? 'Hidden' : 'Shown';
+ }
+ }))}
+ header={false}
+ center={false}
+ >
+ <span slot="title">
+ <input
+ type="text"
+ placeholder="Shown"
+ name="hidden"
+ minlength="1"
+ maxlength="1000"
+ size="15"
+ value={selectedBadge
+ ? selectedBadge.hidden
+ ? 'Hidden'
+ : 'Shown'
+ : 'Shown'}
+ />
+ </span>
+ </Dropdown>
+ <button class="button-lined" on:click={submitBadge}
+ >{selectedBadge
+ ? $locale().user.badges.editMode.update
+ : $locale().user.badges.editMode.add}</button
+ >
+ {#if selectedBadge}
+ {$locale().user.badges.editMode.or}
+ <button
+ class="button-lined"
+ on:click={() => {
+ if (selectedBadge) removeBadge(selectedBadge);
+ }}>{$locale().user.badges.editMode.delete}</button
+ >
+ {/if}
+ </div>
+ {/if}
+ {/if}
+ </div>
+ {/if}
+
+ <p />
+
+ <Badges
+ {ungroupedBadges}
+ {groupedBadges}
+ {categoryFilter}
+ {editMode}
+ {preferences}
+ bind:selectedBadge
+ />
+ {/if}
+ </div>
+
+ {#if isBadgeSelected}
+ <!-- {@const anyAdjacentBadgeExists =
adjacentBadgeExists(selectedBadge, ungroupedBadges, -1) ||
adjacentBadgeExists(selectedBadge, ungroupedBadges, 1)} -->
- <Popup
- fullscreen
- show={isBadgeSelected}
- onLeave={() => {
- selectedBadge = undefined;
- }}
- >
- <BadgePreview
- bind:selectedBadge
- onNext={() => setAdjacentCursor(ungroupedBadges, 1)}
- onPrevious={() => setAdjacentCursor(ungroupedBadges, -1)}
- hasNext={adjacentBadgeExists(selectedBadge, ungroupedBadges, 1) !== undefined}
- hasPrevious={adjacentBadgeExists(selectedBadge, ungroupedBadges, -1) !== undefined}
- />
-
- {#if authorised}
- <button on:click={shadowHideBadge}>
- {#if selectedBadge && selectedBadge.shadow_hidden}
- Un-shadow
- {:else}
- Shadow
- {/if} Hide Badge ({selectedBadge ? selectedBadge.id : 0})
- </button>
- {/if}
- </Popup>
- {/if}
- {/if}
+ <Popup
+ fullscreen
+ show={isBadgeSelected}
+ onLeave={() => {
+ selectedBadge = undefined;
+ }}
+ >
+ <BadgePreview
+ bind:selectedBadge
+ onNext={() => setAdjacentCursor(ungroupedBadges, 1)}
+ onPrevious={() => setAdjacentCursor(ungroupedBadges, -1)}
+ hasNext={adjacentBadgeExists(selectedBadge, ungroupedBadges, 1) !== undefined}
+ hasPrevious={adjacentBadgeExists(selectedBadge, ungroupedBadges, -1) !== undefined}
+ />
+
+ {#if authorised}
+ <button on:click={shadowHideBadge}>
+ {#if selectedBadge && selectedBadge.shadow_hidden}
+ Un-shadow
+ {:else}
+ Shadow
+ {/if} Hide Badge ({selectedBadge ? selectedBadge.id : 0})
+ </button>
+ {/if}
+ </Popup>
+ {/if}
+ {/if}
{/if}
{#if true}
- <Popup fullscreen onLeave={() => (importMode = false)} show={importMode}>
- {$locale().user.badges.importMode.title}
-
- <p />
-
- <input
- type="text"
- placeholder={$locale().user.badges.editMode.activityURL}
- id="import_activity_url"
- minlength="1"
- maxlength="1000"
- size="20"
- />
- <input
- type="text"
- placeholder={$locale().user.badges.editMode.category}
- id="import_category"
- minlength="1"
- maxlength="1000"
- size="20"
- />
-
- <p />
-
- <input type="checkbox" id="import_links" name="import_links" bind:checked={importLinks} />
- {$locale().user.badges.importMode.importLinks.title}
- <SettingHint lineBreak>
- {$locale().user.badges.importMode.importLinks.hint}
- </SettingHint>
-
- <p />
-
- <input type="checkbox" id="import_links" name="import_links" bind:checked={importReplies} />
- {$locale().user.badges.importMode.importReplies}
-
- <p />
-
- <button
- on:click={() => {
- importMode = false;
- importImages = undefined;
- }}
- class="button-lined"
- >
- {$locale().user.badges.importMode.cancel}
- </button>
- <button on:click={() => parsePost()} class="button-lined" style="float: right;">
- {$locale().user.badges.importMode.fetch}
- </button>
-
- <p />
-
- <details>
- <summary>{$locale().user.badges.importMode.dangerous}</summary>
-
- <button
- class="button-lined no-shadow"
- data-umami-event="Remove All Badges"
- on:click={removeAllBadges}
- >
- {$locale({
- values: {
- times: 3 - confirmPrune
- }
- }).user.badges.importMode.deleteAll.title}
- </button>
- <SettingHint lineBreak>
- {$locale().user.badges.importMode.deleteAll.hint}
- </SettingHint>
- </details>
-
- {#if importImages && importImages.length > 0}
- <p />
-
- {$locale({
- values: {
- count: importImages.length
- }
- }).user.badges.importMode.importConfirm}&nbsp;
- <button
- on:click={() => importBadges()}
- class="button-lined no-shadow"
- data-umami-event="Import Badges"
- >
- {$locale().user.badges.importMode.import}
- </button>
-
- <SettingHint lineBreak>
- {$locale().user.badges.importMode.importWait}
- </SettingHint>
- {/if}
- </Popup>
+ <Popup fullscreen onLeave={() => (importMode = false)} show={importMode}>
+ {$locale().user.badges.importMode.title}
+
+ <p />
+
+ <input
+ type="text"
+ placeholder={$locale().user.badges.editMode.activityURL}
+ id="import_activity_url"
+ minlength="1"
+ maxlength="1000"
+ size="20"
+ />
+ <input
+ type="text"
+ placeholder={$locale().user.badges.editMode.category}
+ id="import_category"
+ minlength="1"
+ maxlength="1000"
+ size="20"
+ />
+
+ <p />
+
+ <input type="checkbox" id="import_links" name="import_links" bind:checked={importLinks} />
+ {$locale().user.badges.importMode.importLinks.title}
+ <SettingHint lineBreak>
+ {$locale().user.badges.importMode.importLinks.hint}
+ </SettingHint>
+
+ <p />
+
+ <input type="checkbox" id="import_links" name="import_links" bind:checked={importReplies} />
+ {$locale().user.badges.importMode.importReplies}
+
+ <p />
+
+ <button
+ on:click={() => {
+ importMode = false;
+ importImages = undefined;
+ }}
+ class="button-lined"
+ >
+ {$locale().user.badges.importMode.cancel}
+ </button>
+ <button on:click={() => parsePost()} class="button-lined" style="float: right;">
+ {$locale().user.badges.importMode.fetch}
+ </button>
+
+ <p />
+
+ <details>
+ <summary>{$locale().user.badges.importMode.dangerous}</summary>
+
+ <button
+ class="button-lined no-shadow"
+ data-umami-event="Remove All Badges"
+ on:click={removeAllBadges}
+ >
+ {$locale({
+ values: {
+ times: 3 - confirmPrune
+ }
+ }).user.badges.importMode.deleteAll.title}
+ </button>
+ <SettingHint lineBreak>
+ {$locale().user.badges.importMode.deleteAll.hint}
+ </SettingHint>
+ </details>
+
+ {#if importImages && importImages.length > 0}
+ <p />
+
+ {$locale({
+ values: {
+ count: importImages.length
+ }
+ }).user.badges.importMode.importConfirm}&nbsp;
+ <button
+ on:click={() => importBadges()}
+ class="button-lined no-shadow"
+ data-umami-event="Import Badges"
+ >
+ {$locale().user.badges.importMode.import}
+ </button>
+
+ <SettingHint lineBreak>
+ {$locale().user.badges.importMode.importWait}
+ </SettingHint>
+ {/if}
+ </Popup>
{/if}
<Popup fullscreen onLeave={() => (migrateMode = false)} show={migrateMode}>
- Migrate Category
-
- <p />
-
- <input
- type="text"
- placeholder="Original Category"
- id="migrate_original"
- minlength="1"
- maxlength="1000"
- size="20"
- />
- <input
- type="text"
- placeholder="New Category"
- id="migrate_new"
- minlength="1"
- maxlength="1000"
- size="20"
- />
- <SettingHint lineBreak>Leave category empty to migrate all to or from uncategorised.</SettingHint>
-
- <p />
-
- <button
- on:click={() => {
- importMode = false;
- importImages = undefined;
- }}
- class="button-lined"
- >
- {$locale().user.badges.importMode.cancel}
- </button>
- <button on:click={() => migrateCategory()} class="button-lined" style="float: right;">
- Migrate
- </button>
+ Migrate Category
+
+ <p />
+
+ <input
+ type="text"
+ placeholder="Original Category"
+ id="migrate_original"
+ minlength="1"
+ maxlength="1000"
+ size="20"
+ />
+ <input
+ type="text"
+ placeholder="New Category"
+ id="migrate_new"
+ minlength="1"
+ maxlength="1000"
+ size="20"
+ />
+ <SettingHint lineBreak>Leave category empty to migrate all to or from uncategorised.</SettingHint>
+
+ <p />
+
+ <button
+ on:click={() => {
+ importMode = false;
+ importImages = undefined;
+ }}
+ class="button-lined"
+ >
+ {$locale().user.badges.importMode.cancel}
+ </button>
+ <button on:click={() => migrateCategory()} class="button-lined" style="float: right;">
+ Migrate
+ </button>
</Popup>
<Popup fullscreen onLeave={() => (hideMode = false)} show={hideMode}>
- Hide Category
-
- <SettingHint lineBreak>
- If the majority of the badges in a category are shown, the category will be hidden, and vice
- versa.
- </SettingHint>
-
- <p />
-
- <input
- type="text"
- placeholder="Category"
- id="category_hide"
- minlength="1"
- maxlength="1000"
- size="20"
- />
- <SettingHint lineBreak>Leave category field empty to hide all.</SettingHint>
-
- <p />
-
- <button
- on:click={() => {
- hideMode = false;
- importImages = undefined;
- }}
- class="button-lined"
- >
- {$locale().user.badges.importMode.cancel}
- </button>
- <button on:click={() => hideCategory()} class="button-lined" style="float: right;"
- >Toggle Visibility</button
- >
+ Hide Category
+
+ <SettingHint lineBreak>
+ If the majority of the badges in a category are shown, the category will be hidden, and vice
+ versa.
+ </SettingHint>
+
+ <p />
+
+ <input
+ type="text"
+ placeholder="Category"
+ id="category_hide"
+ minlength="1"
+ maxlength="1000"
+ size="20"
+ />
+ <SettingHint lineBreak>Leave category field empty to hide all.</SettingHint>
+
+ <p />
+
+ <button
+ on:click={() => {
+ hideMode = false;
+ importImages = undefined;
+ }}
+ class="button-lined"
+ >
+ {$locale().user.badges.importMode.cancel}
+ </button>
+ <button on:click={() => hideCategory()} class="button-lined" style="float: right;"
+ >Toggle Visibility</button
+ >
</Popup>